using System;
using System.IO;
using System.Linq;
using Lucene.Net.Index;
using Lucene.Net.Documents;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Search;
using Lucene.Net.QueryParsers;
using Lucene.Net.Store;
using IO = System.IO;

namespace SpeedSearch.FullText
{

    public class FTIndexer : IDisposable
    {

        readonly static SimpleFSLockFactory _LockFactory = new SimpleFSLockFactory();
        private string directory;
        IndexWriter writer;
        Analyzer analyzer;
        Lucene.Net.Store.Directory indexDir;
        bool optimize;

        //public string[] Patterns = { "*.doc", "*.xls", "*.ppt", "*.htm", "*.txt" };

        public FTIndexer(string directory, bool optimize)
        {
            this.directory = directory;
            if (!IO.Directory.Exists(directory))
                IO.Directory.CreateDirectory(directory);

            this.optimize = optimize;
            analyzer = new StandardAnalyzer(Program.LVersion);
            indexDir = FSDirectory.Open(new DirectoryInfo(directory));
            //indexDir = FSDirectory.Open(new DirectoryInfo(directory), _LockFactory);
            // s� cria se n�o existirem dados
            writer = new IndexWriter(indexDir, analyzer, System.IO.Directory.GetFiles(directory).Length == 0, new IndexWriter.MaxFieldLength(Int32.MaxValue));
            writer.UseCompoundFile = true;
        }

        public void AddDocument(FileInfo f, Int64 indexId, int dirId)
        {
            Document doc = new Document();
            SetFields(doc, f, indexId, dirId);
            writer.AddDocument(doc);
        }

        public void UpdateDocument(Document doc, FileInfo f, Int64 indexId, int dirId)
        {
            DeleteFields(doc);
            SetFields(doc, f, indexId, dirId);
        }

        public void DeleteFields(Document doc)
        {
            var list = doc.GetFields().ToList();
            foreach (Field field in list)
                doc.RemoveField(field.Name);
        }

        public void DeleteDocuments(Query query)
        {
            writer.DeleteDocuments(query);
        }

        public void SetFields(Document doc, FileInfo f, Int64 indexId, int dirId)
        {
            doc.Add(new Field("id", indexId.ToString(), Field.Store.YES, Field.Index.ANALYZED)); // IndexId
            doc.Add(new Field("dir", dirId.ToString(), Field.Store.YES, Field.Index.ANALYZED)); // DirId
            doc.Add(new Field("name", f.Name, Field.Store.NO, Field.Index.ANALYZED)); // FileName
            doc.Add(new Field("ext", f.Extension.ToLower().Replace(".", ""), Field.Store.NO, Field.Index.ANALYZED)); // Extension
            doc.Add(new Field("fname", f.FullName, Field.Store.YES, Field.Index.ANALYZED)); // FullName
            doc.Add(new Field("size", f.Length.ToString(), Field.Store.YES, Field.Index.ANALYZED)); // FileSize
            doc.Add(new Field("create", DateTools.DateToString(f.CreationTime, DateTools.Resolution.SECOND), Field.Store.YES, Field.Index.ANALYZED)); // Created
            doc.Add(new Field("modif", DateTools.DateToString(f.LastWriteTime, DateTools.Resolution.SECOND), Field.Store.YES, Field.Index.ANALYZED)); // Modified
            // conteúdo
            // doc.Add(new Field("text", File.ReadAllText(f.FullName, System.Text.UTF8Encoding.UTF8), Field.Store.NO, Field.Index.ANALYZED));
            // Usar o StreamReader ao invés de usar o texto, que consome bem menos memória e evita o erro de OutOfMemory do Lucene.Net
            var reader = new StreamReader(f.FullName, true);
            doc.Add(new Field("text", reader)); //, Field.Store.NO, Field.Index.ANALYZED));

        }

        public void Dispose()
        {
            if (optimize) writer.Optimize();
            writer.Dispose();
            writer = null;
        }
    }

    /*
    public class IndexResult
    {
        public long Bytes;
        public int Total;
        public DateTime Start, End;

        public IndexResult()
        {
            Start = DateTime.Now;
        }

        public override string ToString()
        {
            return End.Subtract(Start).ToString();
        }
    }
    */
}
